package org.eenie.qeasy;

import android.app.Activity;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.NestedScrollView;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.polidea.rxandroidble2.RxBleClient;
import com.polidea.rxandroidble2.RxBleConnection;
import com.polidea.rxandroidble2.RxBleDevice;
import com.polidea.rxandroidble2.RxBleDeviceServices;
import com.polidea.rxandroidble2.scan.ScanResult;
import com.polidea.rxandroidble2.scan.ScanSettings;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;

import io.reactivex.SingleObserver;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.observers.DefaultObserver;

public class MainActivity extends AppCompatActivity implements View.OnClickListener, TimeTrack.OnTriggerListener {


    RxBleClient mRxBleClient;

    Button mBtnScan;
    Button mBtnStart;
    Button mBtnConnect;
    Button mBtnWrite;
    TextView mTvLog;
    TextView mTvTime;

    NestedScrollView mScrollView;

    Disposable disposable;

    private Context mContext;


    private int[] colors = new int[]{
            Color.parseColor("#50BB0B6F"),
            Color.parseColor("#505FBB2D"),
            Color.parseColor("#50BBA025"),
            Color.parseColor("#503549FF"),
            Color.parseColor("#50FF133A"),
            Color.parseColor("#5016FFE1"),
            Color.parseColor("#50FFAB00")};





    TimeTrack mTimeTrack;
    List<PulseConfig> mPulseConfigs = new ArrayList<>();

    public static final UUID UUID_SERVICE_CHANNEL = UUID.fromString("0000FFEA-0000-1000-8000-00805f9b34fb");

    public static final UUID UUID_CHARACTERISTIC_CHANNEL = UUID.fromString("0000FFEB-0000-1000-8000-00805f9b34fb");
    public static final UUID UUID_CHARACTERISTIC_CHANNEL_b = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");

    Map<String, RxBleDevice> mBleDeviceMap = new HashMap<>();

    RxBleConnection mRxBleConnection;

    SingleObserver<byte[]> writeObserver = new SingleObserver<byte[]>() {
        @Override
        public void onSubscribe(Disposable d) {

        }

        @Override
        public void onSuccess(byte[] bytes) {
            log("write = " + bytes2HexString(bytes));
        }

        @Override
        public void onError(Throwable e) {
            e.printStackTrace();
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;
        initViews();

        mRxBleClient = RxBleClient.create(this);

    }


    private void initViews() {
        mScrollView = findViewById(R.id.scro_log);


        mBtnConnect = findViewById(R.id.btn_connect);
        mBtnConnect.setOnClickListener(this);

        mBtnScan = findViewById(R.id.btn_scan);
        mBtnScan.setOnClickListener(this);

        mBtnWrite = findViewById(R.id.btn_config);
        mBtnWrite.setOnClickListener(this);

        mTvLog = findViewById(R.id.tv_log);
        mTvTime = findViewById(R.id.tv_time);

        mTimeTrack = findViewById(R.id.time_track);
        mTimeTrack.setPulseConfigs(mPulseConfigs);
        mTimeTrack.setTotalTime(300);
        mTimeTrack.setTriggerListener(this);

        mBtnStart= findViewById(R.id.btn_start);
        mBtnStart.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_scan:
                disposable = mRxBleClient.scanBleDevices(new ScanSettings.Builder()
                        .build())
                        .subscribe(new Consumer<ScanResult>() {
                            @Override
                            public void accept(ScanResult scanResult) throws Exception {
                                if (!mBleDeviceMap.containsKey(scanResult.getBleDevice().getMacAddress())) {
                                    mBleDeviceMap.put(scanResult.getBleDevice().getMacAddress(), scanResult.getBleDevice());
                                    log("found = " + scanResult.getBleDevice().getName() + "(" + scanResult.getBleDevice().getMacAddress() + ")");
                                    if (scanResult.getBleDevice().getMacAddress().equals("0C:B2:B7:16:BE:37")) {
                                        log("listen state change = " + scanResult.getBleDevice().getName() + "(" + scanResult.getBleDevice().getMacAddress() + ")");
                                        disposable.dispose();
                                        mBleDeviceMap.get("0C:B2:B7:16:BE:37")
                                                .observeConnectionStateChanges()
                                                .subscribe(new DefaultObserver<RxBleConnection.RxBleConnectionState>() {
                                                    @Override
                                                    public void onNext(RxBleConnection.RxBleConnectionState rxBleConnectionState) {
                                                        log("device state = " + rxBleConnectionState);
                                                    }

                                                    @Override
                                                    public void onError(Throwable e) {
                                                        e.printStackTrace();
                                                    }

                                                    @Override
                                                    public void onComplete() {

                                                    }
                                                });
                                    }


                                }
                            }
                        }, new Consumer<Throwable>() {
                            @Override
                            public void accept(Throwable throwable) throws Exception {
                                throwable.printStackTrace();
                            }
                        });
                break;

            case R.id.btn_connect:
                mBleDeviceMap.get("0C:B2:B7:16:BE:37")
                        .establishConnection(false)
                        .subscribe(new DefaultObserver<RxBleConnection>() {
                            @Override
                            public void onNext(final RxBleConnection rxBleConnection) {
                                mRxBleConnection = rxBleConnection;


                                rxBleConnection.discoverServices().subscribe(new SingleObserver<RxBleDeviceServices>() {
                                    @Override
                                    public void onSubscribe(Disposable d) {

                                    }

                                    @Override
                                    public void onSuccess(RxBleDeviceServices services) {
                                        for (BluetoothGattService service : services.getBluetoothGattServices()) {
                                            log("service uuid " + service.getUuid());
                                            for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
                                                log("        " + characteristic.getUuid().toString());
                                            }
                                        }
                                    }

                                    @Override
                                    public void onError(Throwable e) {

                                    }
                                });
                            }

                            @Override
                            public void onError(Throwable e) {

                            }

                            @Override
                            public void onComplete() {

                            }
                        });
                break;


            case R.id.btn_config:
                startActivityForResult(new Intent(mContext, AddConfigActivity.class), 1000);
                break;
            case R.id.btn_start:
                if (mRxBleConnection == null) {
                    Toast.makeText(mContext, "设备未连接", Toast.LENGTH_SHORT).show();
                } else {
                    if (mTimeTrack.isStart()) {
                        mTimeTrack.stop();
                    } else {
                        mTimeTrack.start();
                    }
                }
                break;
        }
    }


    private void log(final String msg) {
        Log.e("LOG", "log = " + msg);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mTvLog.append(msg + "\n");
                mScrollView.fullScroll(NestedScrollView.FOCUS_DOWN);
            }
        });
    }


    // byte转十六进制字符串
    public String bytes2HexString(byte[] bytes) {
        String ret = "";
        for (byte item : bytes) {
            String hex = Integer.toHexString(item & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toUpperCase(Locale.CHINA);
        }
//        log("receive = " + ret);
        return ret;
    }

    // 将16进制的字符串转换为字节数组
    public byte[] getHexBytes(String message) {
//        log("write = " + message);
        int len = message.length() / 2;
        char[] chars = message.toCharArray();
        String[] hexStr = new String[len];
        byte[] bytes = new byte[len];
        for (int i = 0, j = 0; j < len; i += 2, j++) {
            hexStr[j] = "" + chars[i] + chars[i + 1];
            bytes[j] = (byte) Integer.parseInt(hexStr[j], 16);
        }
        return bytes;
    }


    @Override
    public void onTrigger(PulseEntity entity) {

        if (mRxBleConnection != null) {
            if (entity.getPulseMode() == PulseMode.START) {
                mRxBleConnection.writeCharacteristic(UUID_CHARACTERISTIC_CHANNEL, getHexBytes(entity.getPulseConfig().command))
                        .subscribe(writeObserver);
            } else {
                mRxBleConnection.writeCharacteristic(UUID_CHARACTERISTIC_CHANNEL, getHexBytes("080700000080"))
                        .subscribe(writeObserver);
            }
        }

    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1000 && resultCode == Activity.RESULT_OK) {
            List<PulseConfig> pulseConfigs = data.getParcelableArrayListExtra("data");
            mTimeTrack.setPulseConfigs(pulseConfigs);
        }
    }

    @Override
    public void onTimeChange(float time) {
        mTvTime.setText(String.valueOf((int) time));
    }
}
